package com.zwh.se.oop.polymorphic;

/**
 * 多态性是OOP中的一个重要特性，主要是用来实现动态联编的，换句话说，就是程序的最终状态只有在
 * 执行过程中才被决定而非在编译期间就决定了。这对于大型系统来说能提高系统的灵活性和扩展性。
 * 多态可以让我们不用关心某个对象到底是什么具体类型，就可以使用该对象的某些方法，从而实现更加
 * 灵活的编程，提高系统的可扩展性。
 * 1、多态是方法的多态，属性没有多态性
 * 2、编写程序时，如果想调用运行时类型的方法，只能进行类型转换。不然通不过编译器的检查。但是
 * 如果两个没有关联的类进行强制转换，会报：ClassCastException。 比如：本来是狗，我把它转成
 * 猫。就会报这个异常。
 * 3. 多态的存在要有3个必要条件：要有继承，要有方法重写，父类引用指向子类对象
 */
class Person{
    private String privateField = "父类变量 --peivate";
    protected String protectedField = "父类变量 --protected";
    public String publicField = "父类变量 --public";
    String friendlyField = "父类变量 --friendly";
    //用final修饰的类不能被继承,没有子类
    //用final修饰的方法可以被继承,但是不能被子类的重写。
    //用final修饰的变量表示常量,只能被赋一次值.其实使用final修饰的变量也就成了常量了,因为值不会再变了。
    public final String finalField = "父类变量 --final";

    public String getPrivateField() {
        return privateField;
    }
    public Person() {
        System.out.println("父类构造器");
    }

    @Override
    public String toString() {
        return "父类toString";
    }
    static {
        System.out.println("父类静态代码块");
    }
    {
        System.out.println("父类代码块");
    }
}
class Student extends Person {
    private String privateField = "子类变量 --peivate";
    protected String protectedField = "子类变量 --protected";
    public String publicField = "子类变量 --public";
    String friendlyField = "子类变量 --friendly";
    public final String finalField = "子类变量 --final";

    //子类继承父类,调用a方法，如果a方法在子类中没有重写,那么就是调用的是子类继承父类的a方法,
    //如果重写了,那么调用的就是重写之后的方法。
    @Override
    public String getPrivateField() {
        return privateField;
    }
    public void test(){
    }
    public Student() {
        System.out.println("子类构造器");
    }
    static {
        System.out.println("子类静态代码块");
    }
    {
        System.out.println("子类代码块");
    }
}

/**
 * todo 双亲委派机制定义：当一个类加载器收到了类加载的请求的时候，他不会直接去加载指定的类，而是把这个请求委托给自己的父加载器去加载。
 *  只有父加载器无法加载这个类的时候，才会由当前这个加载器来负责类的加载。
 */
public class Demo{
    public static void main(String[] args) {
        Person p = new Student();
        Student s = new Student();
        s.test();
//        编译看左边，运行不一定看右边
//        p.test(); //编译报错,因为编译器检查变量p的类型是Person,但是在Person类中并没有发现test方法,所以编译报错.
        System.out.println(p.friendlyField);
        System.out.println(p.protectedField);
        System.out.println(p.publicField);
        System.out.println(p.getPrivateField()); //实际类是字类，所以得到的是字类的属性
        System.out.println(p.finalField);
        System.out.println(p.toString());
        System.out.println("---------------------------------------------------------");
        System.out.println(s.friendlyField);
        System.out.println(s.protectedField);
        System.out.println(s.publicField);
        System.out.println(s.getPrivateField());
        System.out.println(s.finalField);
        System.out.println(s.toString());//没有重写toString方法直接调用父类的方法
    }

}